// 1. promise 有三个状态： 成功（resolve） 失败（reject） 等待（既不成功也不失败， 默认）
// 2. 用户自己决定 失败的原因和 成功的原因 成功 和 失败的原因也是用户定义的
// 3. promise默认执行器 是 立即执行的
// 4. promise 的实例都拥有一个 then 方法, 一个参数 是成功的 回调, 另一个是 失败的回调
// 5. 如果执行函数时 发生啦异常 也会 执行失败逻辑
// 6. 如果 promise 一旦成功就不能失败, 反之亦然  -> 只有等待态  才能去更改状态

const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const PENDING = 'PENDING'

// 所有的 promise 都需要兼容 bluebird q es6-promise
const resolvePromise = (promise2, x, resolve, reject) => {
    // 1. 循环引用 自己等待自己完成 错误的实现
    if (promise2 === x) { // 用一个类型错误  结束掉 promise
        return reject(new Error(`[TypeError: Chaining cycle detected for promise #<Promise>]`))
    }
    // 后续的条件要严格判断 保证代码要和别的库一起使用
    let called
    if ((typeof x === 'object' && x != null) || typeof x === 'function') { // 有可能是一个 promise
        // 要继续判断
        try {  // 别人定义的 promise 可能用 Object.defineProperty 自定义
            let then = x.then
            if (typeof then === 'function') { // 只能认为是一个 promise
                // x.then 可能会出现问题  因为可能会再次取值
                then.call(x, y => { //根据 promise 的状态 决定 是成功还是 失败
                    if (called) return
                    called = true   // 防止 状态多次 改变, 只取 第一次 屏蔽其他
                    resolvePromise(promise2, y, resolve, reject)
                }, e => {
                    if (called) return
                    called = true
                    reject(e)
                })
            } else { // { then: '23' }
                resolve(x)
            }
        } catch (error) {
            if (called) return
            called = true
            reject(e) //取值出错
        }
    } else {
        resolve(x)
    }
}
class Promise {
    constructor(executor) {
        this.status = PENDING
        this.value = undefined
        this.reason = undefined
        this.onResolvedCallBacks = [] //专门用来存放成功的回调
        this.onRejectedCallBacks = [] // 专门用来存放失败的回调
        let resolve = (value) => { // 调用此方法就是成功

            if(value instanceof Promise) {
                return value.then(resolve, reject)  // 递归解析 resolve中的参数, 制导这个值是 普通值
            }

            if (this.status === PENDING) {
                this.value = value
                this.status = RESOLVED
                this.onResolvedCallBacks.forEach(fn => fn())
            }
        }
        let reject = (reason) => { // 调用此方法就是失败
            if (this.status === PENDING) {
                this.reason = reason
                this.status = REJECTED
                this.onRejectedCallBacks.forEach(fn => fn())
            }
        }
        try {
            executor(resolve, reject) //立即执行
        } catch (error) {  // 错误处理 需要直接走 错误逻辑
            console.log(error)
            reject(error)
        }
    }
    // 1. promise 成功 和 失败的 回调的 返回值 可以传递到 外层的下一个 then
    // 2. 如果返回的 是 普通值的话(传递到下一次的成功中, 不是错误 不是 promise 就是普通值), 可能还有 promise 的情况(一定会走到下一次的失败), 出错的情况(会采用promise的状态, 决定走下一次的成功还是失败)
    // 3. 错误处理  如果离自己最忌的 then 没有错误处理(没有写错误处理函数) 会向下找
    // 4. 每次执行完 promise.then 方法后 返回的都是一个"新的 promise" (promise 一旦成功或者失败就不能修改状态)
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
        let promise2 = new Promise((resolve, reject) => {
            if (this.status === RESOLVED) {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value)
                        // x 可能是一个 promise
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            }
            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            }
            if (this.status === PENDING) {
                this.onResolvedCallBacks.push(() => {
                    setTimeout(() => {
                        try {
                            // ...todo
                            let x = onFulfilled(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                })
                this.onRejectedCallBacks.push(() => {
                    setTimeout(() => {
                        try {
                            // ...todo
                            let x = onRejected(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                })
            }
        })  // 为了实现 链式调用
        return promise2
    }

    catch(errCallback) {
        return this.then(null, errCallback)
    }

    static resolve(data) {
        return new Promise((resolve, reject) => {
            resolve(data)
        })
    }

    static reject(reason) {
        return new Promise((resolve, reject) => {
            reject(reason)
        })
    }
}

Promise.defer = Promise.deferred = function () {
    let dfd = {}
    dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve
        dfd.reject = reject
    })
    return dfd
}
// npm install promises-aplus-tests -g
module.exports = Promise

